using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GameAOT;
using Spine;
using Spine.Unity;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class SpineManager : Singleton<SpineManager>
    {
        private SpineManager()
        {
        }

        private bool isEditorMode =>
#if UNITY_EDITOR
            StoryClientUtil.IsEditorMode || BattleClientUtil.IsEditorMode;
#else
            false;
#endif

        private readonly Dictionary<int, SpineEntity> _spineEntities = new Dictionary<int, SpineEntity>();

        private int _createID;
        private bool _groupEnabled;


        public async UniTask<int> GetSpine(Transform parent, string name)
        {
            var rEntity = ClassPool<SpineEntity>.Get();
            rEntity.guid = ++this._createID;
            var rPrefabPath = PathConstant.GetSpinePrefabPath(name);

#if UNITY_EDITOR
            if (this.isEditorMode)
            {
                rEntity.gameObject = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/" + rPrefabPath).Instantiate();
                rEntity.gameObject.AddComponent<EditorSkeletonPlayer>();
            }
            else
#endif
            {
                if (!this._groupEnabled)
                {
                    ManagerCenter.Entity.EnableGroup((int)EntityPoolGroupType.SpineEntity);
                }
                var rPrefabEntity = ManagerCenter.Entity.Get(rPrefabPath, (int)EntityPoolGroupType.SpineEntity) as SpinePrefabEntity;
                await rPrefabEntity.Load();
                rEntity.entity = rPrefabEntity;
                rEntity.gameObject = rPrefabEntity.gameObject;
            }
            if (parent)
            {
                rEntity.gameObject.transform.SetParent(parent);
                rEntity.gameObject.transform.localPosition = Vector3.zero;
                rEntity.gameObject.transform.localScale = Vector3.one;
            }
            var rGraphic = rEntity.gameObject.GetComponent<SkeletonGraphic>();
            if (rGraphic)
            {
                rEntity.type = ESpineType.UI;
                rEntity.graphic = rGraphic;
            }
            else
            {
                var rAnimation = rEntity.gameObject.GetComponent<SkeletonAnimation>();
                if (rAnimation)
                {
                    rEntity.type = ESpineType.Animation;
                    rEntity.animation = rAnimation;
                }
            }
            this._spineEntities[rEntity.guid] = rEntity;
            return rEntity.guid;
        }

        public void PlayAnimation(int guid, string animation, bool loop, int track = 0)
        {
            if (this._spineEntities.TryGetValue(guid, out var rEntity))
            {
                switch (rEntity.type)
                {
                    case ESpineType.Animation:
                    {
                        rEntity.animation.AnimationState.SetAnimation(track, animation, loop);
                        break;
                    }
                    case ESpineType.UI:
                    {
                        rEntity.graphic.AnimationState.SetAnimation(track, animation, loop);
                        break;
                    }
                }
            }
        }

        public SpineEntity GetEntity(int guid)
        {
            return this._spineEntities.TryGetValue(guid, out var rEntity) ? rEntity : null;
        }

        public void Remove(int guid)
        {
            if (this._spineEntities.TryGetValue(guid, out var rEntity))
            {
                this._spineEntities.Remove(guid);
                if (rEntity.entity != null)
                {
                    rEntity.entity.EntityGroup.HideEntity(rEntity.entity);
                }
                else
                {
#if UNITY_EDITOR
                    if (this.isEditorMode)
                    {
                        UnityExtension.SafeDestroy(rEntity.gameObject);
                    }
#endif
                }
                ClassPool<SpineEntity>.Put(rEntity);
            }
        }

        public void Clear()
        {
#if UNITY_EDITOR
            if (this.isEditorMode)
            {
                foreach (var rPair in this._spineEntities)
                {
                    UnityExtension.SafeDestroy(rPair.Value.gameObject);
                }
            }
            else
#endif
            {
                ManagerCenter.Entity.GetEntityGroup((int)EntityPoolGroupType.SpineEntity).HideAll();
                if (this._groupEnabled)
                {
                    ManagerCenter.Entity.DisableGroup((int)EntityPoolGroupType.SpineEntity);
                }
            }
            this._spineEntities.Clear();
        }

#if UNITY_EDITOR
        public static SkeletonDataAsset LoadAsset(string name)
        {
            var rPath = PathConstant.GetSpineAssetPath(name);
            var rAsset = UnityEditor.AssetDatabase.LoadAssetAtPath<SkeletonDataAsset>("Assets/" + rPath);
            return rAsset;
        }
#endif

        public class SpineEntity : IReusableClass
        {
            public int guid;
            public ESpineType type;
            public GameObject gameObject;
            public SkeletonAnimation animation;
            public SkeletonGraphic graphic;
            public SpinePrefabEntity entity;

            public uint MaxStore => 5;

            public void OnReset()
            {
                this.guid = 0;
                this.type = ESpineType.None;
                this.animation = null;
                this.graphic = null;
                this.entity = null;
                this.gameObject = null;
            }
        }


        public class SpinePrefabEntity : Entity
        {
        }
    }


    public enum ESpineType
    {
        None,
        Animation,
        UI,
    }
}